agent: @U0AJM7X8FBR Admin - Privy login data.#14
Conversation
New /privy page showing daily/weekly/monthly login counts and a table of individual logins with email, Privy DID, and timestamp. Adds "View Privy Logins" nav button to AdminDashboard. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
📝 WalkthroughWalkthroughA new Privy Logins feature is added to the admin dashboard, including a dedicated page route, navigation link, data-fetching hook, API utility, table component, and TypeScript types for displaying Privy login statistics filtered by period (daily/weekly/monthly). Changes
Sequence DiagramsequenceDiagram
actor User
participant PLP as PrivyLoginsPage
participant Hook as usePrivyLogins
participant Privy as Privy Auth
participant API as API Server
User->>PLP: Selects period
PLP->>Hook: Calls usePrivyLogins(period)
Hook->>Privy: Retrieves access token
Privy-->>Hook: Returns token
Hook->>API: GET /api/admins/privy?period=X<br/>(with Bearer token)
API-->>Hook: Returns PrivyLoginsResponse
Hook-->>PLP: Returns { data, loading, error }
PLP->>PLP: Renders PrivyLoginsTable<br/>with logins data
PLP-->>User: Displays table with<br/>login records
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (4)
components/PrivyLogins/PrivyLoginsPage.tsx (2)
38-49: Addtype="button"to prevent form submission behavior.While these buttons aren't inside a form currently, explicitly setting
type="button"is a defensive best practice that prevents accidental form submissions if the component is ever wrapped in a form.🔧 Proposed fix
<button key={value} + type="button" onClick={() => setPeriod(value)}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/PrivyLogins/PrivyLoginsPage.tsx` around lines 38 - 49, The rendered period buttons in PrivyLoginsPage (the mapped <button> that calls setPeriod(value) and checks period === value) should explicitly include type="button" to avoid accidental form submission if this component is placed inside a form; update the mapped button element to add type="button" alongside the existing onClick, key, and className attributes.
66-70: Consider sanitizing error messages displayed to users.Directly rendering
error.messagecould expose internal implementation details or sensitive information from API errors. Consider using a generic message with the detailed error logged to console for debugging.🔧 Proposed improvement
{error && ( <div className="rounded-md bg-red-50 p-4 text-sm text-red-700 dark:bg-red-900/20 dark:text-red-400"> - {error instanceof Error ? error.message : "Failed to load Privy logins"} + Failed to load Privy logins. Please try again. </div> )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/PrivyLogins/PrivyLoginsPage.tsx` around lines 66 - 70, The current rendering in PrivyLoginsPage (the error conditional that shows {error instanceof Error ? error.message : "Failed to load Privy logins"}) exposes raw error text; change it to display a sanitized/generic message (e.g., "Failed to load Privy logins. Please try again.") and move detailed information to logs for debugging by calling console.error(error) or a logger when error is present. Optionally implement a small helper like sanitizeErrorMessage or map known error types to user-friendly strings and use that helper in the error render path, while ensuring the original error object is still logged for developers.types/privy.ts (1)
9-13: Consider a discriminated union for error handling.The
statusfield can be"error", but the type still requirestotalandloginsfields. A discriminated union would provide better type safety when handling error responses:type PrivyLoginsSuccessResponse = { status: "success"; total: number; logins: PrivyLoginRow[]; }; type PrivyLoginsErrorResponse = { status: "error"; error: string; }; export type PrivyLoginsResponse = PrivyLoginsSuccessResponse | PrivyLoginsErrorResponse;This is optional if the API always throws on errors before returning a response body with
status: "error".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@types/privy.ts` around lines 9 - 13, Replace the current flat PrivyLoginsResponse type with a discriminated union so callers can statically handle success vs error cases: define PrivyLoginsSuccessResponse (status: "success", total: number, logins: PrivyLoginRow[]) and PrivyLoginsErrorResponse (status: "error", error: string) and export PrivyLoginsResponse = PrivyLoginsSuccessResponse | PrivyLoginsErrorResponse; update any places that assume total/logins exist to narrow on status first.components/PrivyLogins/PrivyLoginsTable.tsx (1)
33-34: Date formatting is locale-dependent.
toLocaleString()without arguments produces output based on the user's browser locale, which may be inconsistent across admin users. Consider using a specific locale or a date formatting library for consistent display.🔧 Optional: Use explicit locale
- {new Date(login.created_at).toLocaleString()} + {new Date(login.created_at).toLocaleString("en-US", { + dateStyle: "medium", + timeStyle: "short", + })}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/PrivyLogins/PrivyLoginsTable.tsx` around lines 33 - 34, The TableCell is rendering dates with new Date(login.created_at).toLocaleString(), which yields locale-dependent output; update the rendering in the PrivyLoginsTable component so the date is formatted consistently (either by using Intl.DateTimeFormat with an explicit locale/format options or a date library like date-fns/format) when displaying login.created_at inside the TableCell; locate the JSX that references login.created_at and replace the toLocaleString() call with a deterministic formatter (or a small helper function) so all admin users see a consistent date/time format.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@components/PrivyLogins/PrivyLoginsTable.tsx`:
- Around line 27-28: The TableRow key in PrivyLoginsTable uses only
login.privy_did which can duplicate for multiple events; change the key to a
stable compound key that includes the timestamp (for example combine
login.privy_did and login.created_at) so each login event is unique. Update the
TableRow key usage in the PrivyLoginsTable (and any related PrivyLoginRow
mapping) to something like a string concat of privy_did and created_at to avoid
duplicate React keys.
---
Nitpick comments:
In `@components/PrivyLogins/PrivyLoginsPage.tsx`:
- Around line 38-49: The rendered period buttons in PrivyLoginsPage (the mapped
<button> that calls setPeriod(value) and checks period === value) should
explicitly include type="button" to avoid accidental form submission if this
component is placed inside a form; update the mapped button element to add
type="button" alongside the existing onClick, key, and className attributes.
- Around line 66-70: The current rendering in PrivyLoginsPage (the error
conditional that shows {error instanceof Error ? error.message : "Failed to load
Privy logins"}) exposes raw error text; change it to display a sanitized/generic
message (e.g., "Failed to load Privy logins. Please try again.") and move
detailed information to logs for debugging by calling console.error(error) or a
logger when error is present. Optionally implement a small helper like
sanitizeErrorMessage or map known error types to user-friendly strings and use
that helper in the error render path, while ensuring the original error object
is still logged for developers.
In `@components/PrivyLogins/PrivyLoginsTable.tsx`:
- Around line 33-34: The TableCell is rendering dates with new
Date(login.created_at).toLocaleString(), which yields locale-dependent output;
update the rendering in the PrivyLoginsTable component so the date is formatted
consistently (either by using Intl.DateTimeFormat with an explicit locale/format
options or a date library like date-fns/format) when displaying login.created_at
inside the TableCell; locate the JSX that references login.created_at and
replace the toLocaleString() call with a deterministic formatter (or a small
helper function) so all admin users see a consistent date/time format.
In `@types/privy.ts`:
- Around line 9-13: Replace the current flat PrivyLoginsResponse type with a
discriminated union so callers can statically handle success vs error cases:
define PrivyLoginsSuccessResponse (status: "success", total: number, logins:
PrivyLoginRow[]) and PrivyLoginsErrorResponse (status: "error", error: string)
and export PrivyLoginsResponse = PrivyLoginsSuccessResponse |
PrivyLoginsErrorResponse; update any places that assume total/logins exist to
narrow on status first.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b1521ae4-a9e7-4c85-8c14-856a036d1f7d
📒 Files selected for processing (7)
app/privy/page.tsxcomponents/Home/AdminDashboard.tsxcomponents/PrivyLogins/PrivyLoginsPage.tsxcomponents/PrivyLogins/PrivyLoginsTable.tsxhooks/usePrivyLogins.tslib/recoup/fetchPrivyLogins.tstypes/privy.ts
| {logins.map((login) => ( | ||
| <TableRow key={login.privy_did}> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if the API response could include duplicate privy_did values
# by looking at API route handler or documentation
fd -t f -e ts -e tsx "privy" | xargs rg -l "api.*admins.*privy" | head -5Repository: recoupable/admin
Length of output: 114
🏁 Script executed:
cat -n lib/recoup/fetchPrivyLogins.tsRepository: recoupable/admin
Length of output: 1234
🏁 Script executed:
cat -n hooks/usePrivyLogins.tsRepository: recoupable/admin
Length of output: 1042
🏁 Script executed:
cat -n components/PrivyLogins/PrivyLoginsTable.tsxRepository: recoupable/admin
Length of output: 1573
🏁 Script executed:
fd -t f -name "privy.ts" -o -name "privy.d.ts" | head -5Repository: recoupable/admin
Length of output: 290
🏁 Script executed:
rg "type PrivyLoginRow|type PrivyLoginsResponse|interface PrivyLogin" --type tsRepository: recoupable/admin
Length of output: 233
🏁 Script executed:
cat -n types/privy.tsRepository: recoupable/admin
Length of output: 430
Using privy_did alone as the React key will cause reconciliation issues.
Since each PrivyLoginRow represents a distinct login event (note the created_at field), the same user can appear multiple times in a single period with different login timestamps. Using only privy_did as the key will produce duplicate keys, causing React reconciliation failures.
Use a compound key that includes created_at:
🔧 Proposed fix
- {logins.map((login) => (
- <TableRow key={login.privy_did}>
+ {logins.map((login) => (
+ <TableRow key={`${login.privy_did}-${login.created_at}`}>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| {logins.map((login) => ( | |
| <TableRow key={login.privy_did}> | |
| {logins.map((login) => ( | |
| <TableRow key={`${login.privy_did}-${login.created_at}`}> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@components/PrivyLogins/PrivyLoginsTable.tsx` around lines 27 - 28, The
TableRow key in PrivyLoginsTable uses only login.privy_did which can duplicate
for multiple events; change the key to a stable compound key that includes the
timestamp (for example combine login.privy_did and login.created_at) so each
login event is unique. Update the TableRow key usage in the PrivyLoginsTable
(and any related PrivyLoginRow mapping) to something like a string concat of
privy_did and created_at to avoid duplicate React keys.
Automated PR from coding agent.
Prompt: @U0AJM7X8FBR Admin - Privy login data.
• actual: I can't review the number of Privy logins on a daily, weekly and monthly basis. I can't see a total count nor a table of the results for any of those time frames.
• requires: Admin codebase has a page where I can review the number of Privy logins on a daily, weekly and monthly basis. I CAN see a total count and a table of the results for any of those time frames.
Summary by CodeRabbit